package com.example.leepong.Game.Engines;

import android.util.Log;

import com.example.leepong.Game.CoordinatesMover;
import com.example.leepong.Game.Engine;
import com.example.leepong.Game.Entities.Ball;
import com.example.leepong.Game.Entities.Racket;
import com.example.leepong.Game.Shapes.Coordinates;
import com.example.leepong.Game.Shapes.FixedRectangle;
import com.example.leepong.Game.Utils.Canceller;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Ichigo on 06/03/14.
 */
public class HumanPlayer implements IPlayer {

    public ArrayList<Float> SpeedHistory = new ArrayList<>(10);
    private Engine _engine;
    public int _tendencyAngle = -90;
    public float _tendency;
    private Racket _racket;
    private boolean _isLeftSide;
    private Canceller _canceller;

    private Coordinates prevCoord;

    public HumanPlayer(Engine engine) {
        _engine = engine;
        prevCoord = new Coordinates(_engine.BottomRacket.Rect.Coord);
        SpeedHistory.add(0f);
        this._canceller = new Canceller();
    }

    @Override
    public void Assign(Racket racket) {
        _racket = racket;
        _isLeftSide = _racket == _engine.TopRacket;
    }

    @Override
    public void TouchTap(Coordinates tapCoords) {
        MoveRaquet(_racket, tapCoords.X);
    }

    @Override
    public void TouchScroll(Coordinates newCoords, Coordinates oldCoords) {
        MoveRaquet(_racket, newCoords.X);
    }

    @Override
    public void TouchZoneTap(Coordinates tapCoords) {
        MoveRaquetSlow(_racket, tapCoords.X);
    }

    @Override
    public void TouchZoneScroll(Coordinates newCoords, Coordinates oldCoords) {
        MoveRaquet(_racket, newCoords.X);
    }

    @Override
    public void Update() {
        CalculateTendency();
    }

    public void MoveRaquetSlow(Racket racket, float touchX) {
        _canceller.Token.IsCancelled = false;
        Coordinates targetCoord = new Coordinates(ComputeRaquetX(racket, touchX), racket.Rect.Coord.Y);
        CoordinatesMover.MoveAsync(racket.Rect.Coord, targetCoord, 20, _canceller.Token);
    }

    public void MoveRaquet(Racket racket, float touchX) {
        _canceller.Token.IsCancelled = true;
        racket.Rect.Coord.X = ComputeRaquetX(racket, touchX);
    }

    private float ComputeRaquetX(Racket racket, float inputX) {
        FixedRectangle landRec = _engine.Land.Rect;
        float halfRaquetWidth = racket.Rect.Width / 2;

        inputX = inputX - halfRaquetWidth;

        inputX = Math.max(inputX, landRec.Left - halfRaquetWidth);
        inputX = Math.min(inputX, landRec.Right - halfRaquetWidth);
        return inputX;
    }

    public void Shoot() {
        Ball ball = _engine.Ball;
        ball.MoveStep = ball.MoveStep * 1.4f;
        ball.ReflectAngleX();
        ApplyDirection();
    }

    private void ApplyDirection() {
        Ball ball = _engine.Ball;

        //  Log.d("----", "rawtendency :" + rawTendency);
        //Log.d("----", "tendency :" + _tendency);
        // ball.MoveStep = ball.MoveStep + ball.MoveStep * (this.tendency / 5);

//        Log.d("----", "ballAngle :" + ball360Angle);
        //Log.d("----", "tendencyAngle :" + this.tendencyAngle);
//        Log.d("----", "##################");
        ball.Angle = (int) ((ball.Angle + ((this._tendency + 1) * this._tendencyAngle)) / (this._tendency + 2));
    }

    public void CalculateTendency() {

        Coordinates raquetCoord = _engine.BottomRacket.Rect.Coord;
        float diffX = raquetCoord.X - prevCoord.X;
        float speed = diffX / _engine.deltaTime;

        // Log.d("----", "speed :" + speed);
        float tendency = speed / _engine.Land.Rect.Width;
        tendency *= 2000;
        tendency = (float) (Math.signum(tendency) * Math.log1p(Math.abs(tendency)));

        if (SpeedHistory.size() == 10) {
            SpeedHistory.remove(0);
        }

        SpeedHistory.add(tendency);
        float avgTendency = calculateAverage(SpeedHistory);

        int tendencyAngle = -90;
        tendencyAngle += (avgTendency / 2) * 90;
        this._tendencyAngle = tendencyAngle;
        this._tendencyAngle = Math.min(-30, Math.max(-150, tendencyAngle));
        this._tendency = Math.abs(avgTendency);
        prevCoord = new Coordinates(_engine.BottomRacket.Rect.Coord);
    }

    private float calculateAverage(List<Float> marks) {
        Float sum = 0f;
        int total = marks.size();
        int overallFactors = 0;

        if (total == 0)
            return 0;
        for (int i = 1; i < total; i++) {
            float mark = marks.get(i);
            int factor = (int) Math.pow(i, 3) + 1;
            overallFactors += factor;
            sum += mark * factor;
        }
        return sum / overallFactors;
    }
}
